// This file is part of OpenTSDB.
// Copyright (C) 2017 TeleDB Development Group.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 2.1 of the License, or (at your
// option) any later version.  This program is distributed in the hope that it
// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
// General Public License for more details.  You should have received a copy
// of the GNU Lesser General Public License along with this program.  If not,
// see <http://www.gnu.org/licenses/>.
package net.opentsdb.tsd.service;

import com.stumbleupon.async.DeferredGroupException;
import net.opentsdb.core.TSDB;
import net.opentsdb.tsd.HttpQuery;
import net.opentsdb.tsd.http.ServiceResponse;
import net.opentsdb.utils.Exceptions;
import org.jboss.netty.handler.codec.http.HttpMethod;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 处理请求模板
 */
public abstract class RpcServiceImpl implements RpcService{

    private static final Logger LOG = LoggerFactory.getLogger(RpcServiceImpl.class);

    protected final TSDB tsdb;
    private final HttpQuery query;
    private final HttpMethod method;
    protected ServiceResponse response;
    protected Object params;

    public RpcServiceImpl(TSDB tsdb, HttpQuery query){
        this.tsdb = tsdb;
        this.query = query;
        method = query.getAPIMethod();
        response = ServiceResponse.builder(true).build();
    }

    public void handle(){
        params = doParse();

        try{
            checks();

            if(method == HttpMethod.GET) doGet();
            else if(method == HttpMethod.POST) doPost();
            else if(method == HttpMethod.DELETE) doDelete();
            else putErrorResponse(false,
                        " 不支持"+method+"类型请求",
                        HttpResponseStatus.METHOD_NOT_ALLOWED,
                        new UnsupportedOperationException("不支持"+method+"操作"));
        }catch (IOException ioe){
            LOG.error("io异常：",ioe);
            putErrorResponse(false,"IO异常："+ioe.getMessage());
        }catch (IllegalArgumentException ie){
            LOG.error("异常：",ie);
            putErrorResponse(false,"请求参数异常："+ie.getMessage());
        }catch (Exception e){
            LOG.error("异常：",e);
            putErrorResponse(false,"发生异常："+e.getMessage());
        }finally {
            doSend();
        }
    }

    /**
     * 默认返还一个map
     *
     * @return
     */
    public Object doParse() {
        Map<String, String> params = new HashMap<>();

        if(method == HttpMethod.GET ||
                (method == HttpMethod.DELETE && !query.hasContent())) {
             for(Map.Entry<String,List<String>> entry:query.getQueryString().entrySet()){
                 if(entry.getValue() != null && entry.getValue().size() > 0){
                     // 参照原始取最后一个数
                     params.put(entry.getKey(), entry.getValue().get(entry.getValue().size()-1));
                 }
             }
        }
        else if(method == HttpMethod.POST && query.hasContent()) {
             params = query.serializer().parseUidRenameV1();
        }

        return params;
    }

    public void doSend() {
        if(response.getError()){
            query.sendReply(query.serializer().formatUidRenameV1(response.getResMap()));
        }else {
            query.sendReply(response.getStatus(),
                    query.serializer().formatUidRenameV1(response.getResMap()));
        }
    }

    public void putErrorResponse(Boolean result, String message){
        putErrorResponse(result, message, HttpResponseStatus.BAD_REQUEST,new Exception());
    }

    public void putErrorResponse(Boolean result, String message,Exception e){
        putErrorResponse(result, message, HttpResponseStatus.BAD_REQUEST,e);
    }

    public void putErrorResponse(Boolean result, String message, HttpResponseStatus status, Exception e){
        Throwable ex;
        if(e instanceof DeferredGroupException){
            ex = Exceptions.getCause((DeferredGroupException)e);
        }else {
            ex = e;
        }

        LOG.error("{} error",query.getApiPath(),ex);

        response = ServiceResponse.builder(result)
                .error(true)
                .message(message+":"+ex.getMessage())
                .status(status)
                .build();
    }

    protected void putResponse(Boolean result, String message){
        response = ServiceResponse.builder(result)
                .message(message)
                .build();
    }

    protected void putResponse(Boolean result, Map<String,String> message){
        response = ServiceResponse.builder(result)
                .response(message)
                .build();
    }

    public HttpQuery getQuery(){
        return query;
    }
}
